/*****************************************************************************************
   
   Copyright (c) Microsoft Corporation. All rights reserved.

   Use of this code sample is subject to the terms of the Microsoft
   Permissive License, a copy of which should always be distributed with
   this file.  You can also access a copy of this license agreement at:
   http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx

 ****************************************************************************************/

using System;

namespace CommandUtils
{
	public class UtilAppMain
	{
		// From WinBase.h
		internal const int FILE_TYPE_DISK = 0x0001;
		internal const int FILE_TYPE_CHAR = 0x0002;
		internal const int FILE_TYPE_PIPE = 0x0003;

		// Note, these are #defines used to extract handles, and are NOT handles.
		internal const int STD_INPUT_HANDLE = -10;
		internal const int STD_OUTPUT_HANDLE = -11;
		internal const int STD_ERROR_HANDLE = -12;

		[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
		internal static extern int GetFileType(IntPtr i_Handle);

		[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError=true)]
		internal static extern IntPtr GetStdHandle(int i_Handle);  // param is NOT a handle, but it returns one!

		public static void RunApplication(CommandUtils.UtilBase i_Application)
		{
			System.Environment.ExitCode = 1;
			
			System.IO.StreamWriter StandardOutputStreamWriter = new System.IO.StreamWriter(System.Console.OpenStandardOutput());
			System.IO.StreamWriter StandardErrorStreamWriter = new System.IO.StreamWriter(System.Console.OpenStandardError());
			
			UtilBase.CheckResult CheckResult = UtilBase.CheckResult.Failed;
			bool Verbose = false;
			
			try
			{
				System.IO.StreamReader StandardInputStreamReader = new System.IO.StreamReader(System.Console.OpenStandardInput());

				// Decide whether the input stream is a console device or whether it's a
				// file or pipe for purposes of deciding whether we can safely
				// read without blocking the user
				IntPtr Handle = GetStdHandle(STD_INPUT_HANDLE);
				int Type = (GetFileType(Handle) & 0x7FFF);
				bool Console = (Type == FILE_TYPE_CHAR);

				i_Application.SetStandardInput(StandardInputStreamReader, Console);
				i_Application.StandardOutput = StandardOutputStreamWriter;
				i_Application.StandardError = StandardErrorStreamWriter;

				// Read & verify commandline parameters
				CheckResult = i_Application.CheckParameters();
				Verbose = i_Application.Verbose;

				switch (CheckResult)
				{
					case UtilBase.CheckResult.Succeeded:
					{
						CheckResult = i_Application.Run();
						break;
					}

					case UtilBase.CheckResult.ShowHelp:
					{
						i_Application.DisplayHelp();
						break;
					}

					case UtilBase.CheckResult.ShowUsage:
					{
						i_Application.DisplayUsage();
						break;
					}

					default:
					{
						break;
					}
				}
			}
			catch (System.Exception exception)
			{
				CheckResult = UtilBase.CheckResult.Failed;
				Exception e = exception;
				while( e != null )
				{
					StandardErrorStreamWriter.WriteLine(e.Message);
					e = e.InnerException;
				}
				if (Verbose)
					StandardErrorStreamWriter.WriteLine("Call Stack:\n" + exception.StackTrace);
			}

			StandardOutputStreamWriter.Flush();
			StandardErrorStreamWriter.Flush();
			
			System.Environment.ExitCode = (CheckResult == UtilBase.CheckResult.Succeeded) ? 0 : 1;
		}
	}
}
